﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace Dycox.Validation
{
    public class PropertyValidationContext : ITypeDescriptorContext
    {
        public PropertyValidationContext(object instance, PropertyDescriptor property)
        {
            if (property == null)
                throw new ArgumentNullException("property");

            _instance = instance;
            _propertyDescriptor = property;
        }

        IContainer ITypeDescriptorContext.Container
        {
            get { return null; }
        }

        object _instance;

        public object Instance
        {
            get { return _instance; }
        }

        void ITypeDescriptorContext.OnComponentChanged()
        {
        }

        bool ITypeDescriptorContext.OnComponentChanging()
        {
            return false;
        }

        PropertyDescriptor _propertyDescriptor;

        public PropertyDescriptor PropertyDescriptor
        {
            get { return _propertyDescriptor; }
        }

        object IServiceProvider.GetService(Type serviceType)
        {
            return null;
        }

        public object GetValue()
        {
            if (_instance == null ||
                _propertyDescriptor == null)
                throw new InvalidOperationException("Either Instance or PropertyDescriptor not specified.");

            return _propertyDescriptor.GetValue(_instance);
        }

        private object _propertyValue;
        private bool _valueCached;

        /// <summary>
        /// Gets the cached value.
        /// </summary>
        public object PropertyValue
        {
            get
            {
                if (!_valueCached)
                {
                    _propertyValue = GetValue();
                    _valueCached = true;
                }
                return _propertyValue;
            }
        }

        private bool? _isCollection;

        internal bool IsCollection
        {
            get
            {
                if (_isCollection == null)
                {
                    Type type = _propertyDescriptor.PropertyType;
                    if (type == typeof(object))
                    {
                        object value = PropertyValue;
                        if (value != null) type = value.GetType();
                    }

                    _isCollection = type.GetInterface("ICollection") == typeof(ICollection);
                }

                return _isCollection.Value;
            }
        }

        internal IEnumerator GetEnumerator()
        {
            if (IsCollection)
            {
                IEnumerable value = PropertyValue as IEnumerable;

                if (value != null)
                    return value.GetEnumerator();
            }
            return null;
        }

        ValidationBehavior? _behavior;

        public ValidationBehavior Behavior
        {
            get
            {
                if (_behavior == null)
                {
                    if (_propertyDescriptor != null)
                    {
                        ValidationBehaviorAttribute vba = (ValidationBehaviorAttribute)_propertyDescriptor.Attributes[typeof(ValidationBehaviorAttribute)];
                        ValidationBehavior behavior =
                            vba == null ? ValidationBehavior.Default : vba.Behavior;
                        _behavior = behavior;
                    }
                    else
                        _behavior = ValidationBehavior.Default;
                }
                return _behavior.Value;
            }
        }

    }
}
